package pckg;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;

import org.neuroph.core.NeuralNetwork;
import org.neuroph.core.Weight;
import org.neuroph.core.data.DataSet;
import org.neuroph.core.data.DataSetRow;
import org.neuroph.nnet.MultiLayerPerceptron;

public class myNeuralNetwork {

	private MultiLayerPerceptron mlp;
	private final String folder;
	private String mlpSourceFile;
	
	private double[][] input;
	private double[][] output;
	
	private int numberOfInputs = 6;
	private int numberOfOutputs = 2;
	
	public myNeuralNetwork(String folder){
		
		InputStream inputstream = null;
		this.folder = folder;
		mlpSourceFile = folder + "/" + folder + ".nnet";
		try {
			inputstream = new FileInputStream(mlpSourceFile);
			mlp = (MultiLayerPerceptron) NeuralNetwork.load(inputstream);
			System.out.println("MLP loaded succesfully from file: " + mlpSourceFile);
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		loadWeights();
		//loadSamples();
		//double mse = getMSE(input,output);
		//System.out.println(mse);
		
		/*
		mlp.randomizeWeights();
		DataSet ds = loadSamplesToDataSet();
		long start = System.nanoTime();
		mlp.learn(ds);
		long end = System.nanoTime();
		System.out.println("Learning done in: " + (end-start)/1000000.0);
		testNeuralNetwork(ds);
		*/
		
	}
	
	public void testNeuralNetwork(DataSet tset) {
		double mse = 0;
		for(DataSetRow dataRow : tset.getRows()) {
	
			mlp.setInput(dataRow.getInput());
			mlp.calculate();
			double[] nnOut = mlp.getOutput();
			double[] realOut = dataRow.getDesiredOutput();
			mse += (nnOut[0]-realOut[0])*(nnOut[0]-realOut[0]) +
					(nnOut[1]-realOut[1])*(nnOut[1]-realOut[1]);
		}
		
		mse /= 2;
		mse /= input.length;
		
		System.out.println(mse);
	}
	
	public double getMSE(double[][] input, double[][] output){
		double mse = 0;
		double[] tmp = new double[2];
		
		for (int i = 0; i < input.length; i++){
			
			tmp = evaluate(input[i]);
			mse += (tmp[0]-output[i][0])*(tmp[0]-output[i][0]) +
					(tmp[1]-output[i][1])*(tmp[1]-output[i][1]);
			
		}
		
		mse /= 2;
		mse /= input.length;
		
		return mse;
	}
	
	public double[] evaluate(double[] input){
		mlp.setInput(input);
		mlp.calculate();
		
		return mlp.getOutput();
	}
	
	public DataSet loadSamplesToDataSet(){
		String fileName = "PP.txt";
		BufferedReader br;
		
		DataSet ds = new DataSet(numberOfInputs,numberOfOutputs);
		
		try {
			/*
			LineNumberReader  lnr = new LineNumberReader(new FileReader(fileName););
			lnr.skip(Long.MAX_VALUE);
			
			int numberOfSamples = lnr.getLineNumber();
			*/
			int numberOfSamples = 15000;
			input = new double[numberOfSamples][numberOfInputs];
			output = new double[numberOfSamples][numberOfOutputs];
			
			br = new BufferedReader(new FileReader(fileName));
			
	        String line = "";
	        int row = 0;
	        
			while ((line = br.readLine()) != null) 
			{   
				String[] vals = line.split(" ");
				double[] tmpIn = new double[6];
		        double[] tmpOut = new double[2];
			    for (int i = 0; i < vals.length-3; i++){
			    	tmpIn[i] = Double.parseDouble(vals[i]);
			    }
			    for (int i = vals.length-3; i < vals.length-1; i++){
			    	tmpOut[i-numberOfInputs+1] = Double.parseDouble(vals[i]);
			    }
			    tmpIn[numberOfInputs-1] = Double.parseDouble(vals[vals.length-1]);
			    row++;
			    ds.addRow(new DataSetRow(tmpIn,tmpOut));
			}
			
			br.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return ds;
	}
	
	public void loadSamples(){
		String fileName = "PP.txt";
		BufferedReader br;
		
		try {
			/*
			LineNumberReader  lnr = new LineNumberReader(new FileReader(fileName););
			lnr.skip(Long.MAX_VALUE);
			
			int numberOfSamples = lnr.getLineNumber();
			*/
			int numberOfSamples = 15000;
			input = new double[numberOfSamples][numberOfInputs];
			output = new double[numberOfSamples][numberOfOutputs];
			
			br = new BufferedReader(new FileReader(fileName));
			
	        String line = "";
	        int row = 0;
			while ((line = br.readLine()) != null) 
			{   
				String[] vals = line.split(" ");
			    for (int i = 0; i < vals.length-3; i++){
			    	input[row][i] = Double.parseDouble(vals[i]);
			    }
			    for (int i = vals.length-3; i < vals.length-1; i++){
			    	output[row][i-numberOfInputs+1] = Double.parseDouble(vals[i]);
			    }
			    input[row][numberOfInputs-1] = Double.parseDouble(vals[vals.length-1]);
			    row++;
			}
			
			br.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void loadWeights(){
		
		for (int i = 1; i < 5; i++){
			
			String fileName = folder + "/l" + i + ".txt";
			String biasFile = folder + "/b" + i + ".txt";
			loadLayerWeights(i,fileName, biasFile);
		}
		
		//mlp.getLayerAt(4).getNeuronAt(0).setTransferFunction(new Linear(1.3333));
		//mlp.getLayerAt(4).getNeuronAt(1).setTransferFunction(new Linear(1.3333));
	}
	
	public void loadLayerWeights(int layer, String fileName, String biasFile){
		
		try {
			
	        BufferedReader br = new BufferedReader(new FileReader(fileName));
	        String line = "";

	        int row = 0;
	        int numberOfNeuronsInPrevLayer = mlp.getLayerAt(layer-1).getNeuronsCount();
			while ((line = br.readLine()) != null) 
			{   
			    
				String[] vals = line.split("  ");
			    for (int i = 1; i < vals.length; i++){
			    	
			    	double num = Double.parseDouble(vals[i]);
			    	mlp.getLayerAt(layer).
			    		getNeuronAt(row).
			    		getInputConnections()[i-1].
			    		setWeight(new Weight(num));
			    }

			    row++;
			}
			
			br.close();
			
			br = new BufferedReader(new FileReader(biasFile));
	        line = "";

	        row = 0;
	        
			while ((line = br.readLine()) != null) 
			{   
			    
		    	double num = Double.parseDouble(line);
		    	mlp.getLayerAt(layer).
		    		getNeuronAt(row).
		    		getInputConnections()[numberOfNeuronsInPrevLayer-1].
		    		setWeight(new Weight(num));
			    row++;
			}
			
			br.close();
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
